package com.vanke.devops.domain.base;

import com.baomidou.mybatisplus.plugins.Page;
import com.vanke.core.exception.VankeBusinessException;
import com.vanke.core.exception.VankeCommonExCodeEnum;
import com.vanke.core.util.DataUtil;
import com.vanke.devops.dal.base.BaseMapper;
import com.vanke.devops.dal.base.BaseModel;
import com.vanke.devops.dal.util.collection.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author 陈景阳
 * @since 2017/12/4
 */
public class BaseServiceImpl<M extends BaseMapper<T>, T> implements IBaseService<T> {
    protected final Log logger = LogFactory.getLog(getClass());

    @Autowired
    protected M baseMapper;

    @Override
    public void logicDel(Integer id) throws VankeBusinessException {
        try {
            BaseModel record = (BaseModel) this.queryById(id);
            Integer userId = getCurrUser();
            record.setDelFlg(0);
            record.setUpdateTime(new Date());
            record.setUpdateBy(userId);
            baseMapper.updateById((T) record);
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new VankeBusinessException(VankeCommonExCodeEnum.DB_DELETE_ERROR);
        }
    }

    public void logicDel(BaseModel record) throws VankeBusinessException {
        try {
            Integer userId = getCurrUser();
            record.setDelFlg(0);
            record.setUpdateTime(new Date());
            record.setUpdateBy(userId);
            baseMapper.updateById((T) record);
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new VankeBusinessException(VankeCommonExCodeEnum.DB_DELETE_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void delete(Integer id) {
        try {
            baseMapper.deleteById(id);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    @Override
    public T update(T record) throws VankeBusinessException {
        try {
            BaseModel baseModel = (BaseModel) record;
            baseModel.setUpdateTime(new Date());
            Integer userId = getCurrUser();
            baseModel.setUpdateBy(userId);
            baseMapper.updateById(record);
        } catch (DuplicateKeyException e) {
            throw new VankeBusinessException(VankeCommonExCodeEnum.DUPLICATE_KEY_ERROR);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new VankeBusinessException((VankeCommonExCodeEnum.SYS_TOO_BUSY));
        }
        return record;
    }

    @Override
    public boolean add(T record) throws VankeBusinessException {
        try {
            Integer userId = getCurrUser();
            BaseModel baseModel = (BaseModel) record;
            baseModel.setCreateBy(userId);
            baseModel.setUpdateBy(userId);
            baseModel.setUpdateTime(new Date());
            baseModel.setCreateTime(new Date());
            baseModel.setDelFlg(1);
            baseMapper.insert(record);
        } catch (DuplicateKeyException e) {
            throw new VankeBusinessException(VankeCommonExCodeEnum.DUPLICATE_KEY_ERROR);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new VankeBusinessException((VankeCommonExCodeEnum.SYS_TOO_BUSY));
        }
        return true;
    }


    protected void buildInsertBaseModel(BaseModel baseModel) {
        Integer userId = getCurrUser();
        baseModel.setCreateBy(userId);
        baseModel.setCreateTime(new Date());
        baseModel.setDelFlg(1);
    }

    protected void buildUpdateBaseModel(BaseModel baseModel) {
        Integer userId = getCurrUser();
        baseModel.setUpdateBy(userId);
        baseModel.setUpdateTime(new Date());
    }


    @Override
    @SuppressWarnings("unchecked")
    public T queryById(Integer id) {
        try {
            T record = baseMapper.selectById(id);
            return record;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage(), e);
        }
    }


    @Override
    public List<T> queryByIds(List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.EMPTY_LIST;
        }
        return baseMapper.selectBatchIds(ids);
    }

    @Override
    public <O> List<T> queryByNIds(List<O> ids, String normalCol, T param) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.EMPTY_LIST;
        }
        return baseMapper.selectByNIds(ids, param, normalCol);
    }

    @Override
    public <O> List<T> queryByNIds(List<O> ids, String normalCol) {
        Type genType = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        Class<T> tClass = (Class<T>) params[1];

        try {
            return queryByNIds(ids, normalCol, tClass.newInstance());
        } catch (Exception e) {
            logger.error(e);
            throw new RuntimeException("获取列表数据失败");
        }
    }

    @Override
    public List<T> queryList(Map<String, Object> params) {
        return baseMapper.selectRecords(params);
    }

    @Override
    public List<T> queryListByFieldsOrKeyword(T param) {
        return baseMapper.selectRecords(param);
    }


    @Override
    public Page<T> queryPage(Map<String, Object> param) {
        Page<T> page = getPage(param);
        List<T> records = baseMapper.selectRecords(page, param);
        page.setRecords(records);
        return page;
    }

    @Override
    public Page<T> queryPageByFieldsOrKeyword(Integer pageNo, Integer pageSize, T param) {
        if (pageNo == null) {
            pageNo = 1;
        }
        if (pageSize == null) {
            pageSize = 10;
        }
        BaseModel model = (BaseModel) param;
        String orderBy = DataUtil.isNotEmpty(model.getOrderBy()) ? camelToUnderline(model.getOrderBy()) : "id";
        Boolean asc = DataUtil.isNotEmpty(model.getAsc()) ? model.getAsc() : false;
        Page<T> page = getPage(pageNo, pageSize, orderBy, asc);
        List<T> records = baseMapper.selectRecords(page, param);
        page.setRecords(records);
        return page;
    }

    /**
     * 分页查询
     */
    @Override
    public <K> Page<K> getPage(Map<String, Object> params) {
        Integer current = 1;
        Integer size = 10;
        String orderBy = "id";
        Boolean asc = false;
        if (DataUtil.isNotEmpty(params.get("pageNo"))) {
            current = Integer.valueOf(params.get("pageNo").toString());
        }
        if (DataUtil.isNotEmpty(params.get("pageSize"))) {
            size = Integer.valueOf(params.get("pageSize").toString());
        }
        if (DataUtil.isNotEmpty(params.get("orderBy"))) {
            orderBy = (String) params.get("orderBy");
            orderBy = camelToUnderline(orderBy);
        }
        if (DataUtil.isNotEmpty(params.get("asc"))) {
            asc = (Boolean) params.get("asc");
        }
        if (size == -1) {
            return new Page<K>();
        }
        Page<K> page = new Page<K>(current, size, orderBy);
        page.setAsc(asc);
        return page;
    }

    /**
     * 分页查询
     */
    @Override
    public <K> Page<K> getPage(Integer pageNo, Integer pageSize, String orderBy, Boolean asc) {
        if (DataUtil.isEmpty(pageNo)) {
            pageNo = 1;
        }
        if (DataUtil.isEmpty(pageSize)) {
            pageSize = 10;
        }
        Page<K> page = null;
        if (DataUtil.isEmpty(orderBy)) {
            orderBy = "id";
        } else {
            orderBy = camelToUnderline(orderBy);
        }
        page = new Page<K>(pageNo, pageSize, orderBy);
        if (null == asc) {
            asc = false;
        }
        page.setAsc(asc);
        return page;
    }

    public String camelToUnderline(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append('_');
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 获取当前用户Id
     */
    @Override
    public Integer getCurrUser() {
        return (Integer)SecurityUtils.getSubject().getPrincipal();
    }
}
